import cv2 as cv
import numpy as np

# ------------------------harris角点检测---------------------

img = cv.imread('1.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 灰度化

gray = np.float32(gray) # 转换为float32

# harris角点检测
dst = cv.cornerHarris(gray, 7, 7, 0.11) # 计算角点
# 参数说明：
# 1.必须是float32类型
# 2.blockSize: 用于检测角点的窗口尺寸
# 3.ksize: Sobel算子的卷积核大小，一般取3、5、7...，单位像素
# 4.k: Harris角点检测的自由参数，经验系数。通常是 0.04 - 0.25，较高的值（如 0.1 - 0.2）
# 会减少误检，较低的值（如 0.04 - 0.06）则能提高对角点的敏感度。
# 返回值：返回矩阵。在这个矩阵里，每一个像素值都代表着该点是角点的可能性，像素值越高，成为角点的可能性就越大。

print(dst)

# 角点阈值化
img[dst > 0.1*dst.max()] = [0, 0, 255] # 阈值化
# 1.将响应矩阵dst中的最大值乘以0.001，得到一个阈值。通过比较dst中的每个像素值和这个阈值，会生成一个布尔型的掩码矩阵。
# 2.在这个掩码矩阵中，符合条件（像素值大于阈值）的位置为True，不符合条件的为False。
# 3.把掩码矩阵中值为True的位置所对应的像素点，其颜色修改为红色。
# 提示：阈值系数：该系数的大小会直接影响到角点检测的数量。如果把系数调小，比如设为 0.0001，
# 那么就会有更多的点被标记为角点，可能会导致误检；相反，如果把系数调大，像设为 0.01，
# 就只有响应非常强的点才会被标记为角点，这样可能会遗漏一些真实的角点。

#到这里，角点检测已经完成，已经得到每个角点区域的坐标集合（不是一个坐标点），下面会提取出这个区域中心点坐标。
cv.imshow('dst', img)  
cv.waitKey(0)

# 创建二值图像，提取红色区域
red_mask = np.all(img == [0, 0, 255], axis=-1).astype(np.uint8) * 255

# 寻找轮廓
contours, _ = cv.findContours(red_mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

# 计算每个轮廓的中心点
centers = []
for contour in contours:
    M = cv.moments(contour)
    if M["m00"] != 0:  # 避免除零错误
        cX = int(M["m10"] / M["m00"])
        cY = int(M["m01"] / M["m00"])
        centers.append((cX, cY))
        
        # 在原图上标记中心点（可选）
        cv.circle(img, (cX, cY), 2, (0, 255, 0), -1)

# 输出中心点坐标
for i, (x, y) in enumerate(centers):
    print(f"角点 {i+1}: 坐标 ({x}, {y})")

cv.imshow('dst', img)
cv.waitKey(0)
cv.destroyAllWindows()
